Мне давно было интересно как устроен всеми любимый jQuery и вот я решил засесть за него (благо что исходники у него открытые).
И вот, по просьбе камрада mishka2 я рассказываю, что я выяснил, как работает этот фреймворк и как написать свой такой же.
Прежде всего пара фишек яваскрипта, про которые не все начинающие знают:
1) Имена функций:
В яваскрипте валидными считаются любые имена функций, которые начинаются с буквы, со знака доллара ($) и со знака подчеркивания (_). Так что когда вы используете ваш любимый jQuery, вызывая к примеру $(document), знайте, что вы вызываете функцию у которой имя $ и передаете ей в качестве аргумента document.
2) Вызов функций:
Обычно все пишут какую-нибудь функцию, к примеру:
function myFunc() { alert(1); }
// или так var myFunc = function() { alert(1); }
а потом вызывают ее, но многие не знают, что в яваскрипте можно вызвать функцию сразу при создании вот таким методом:
(function() { // создаем функцию alert(1); })(); // и тут же вызываем ее
3) Переменные и функции:
Яваскрипт - это объектно ориентированный язык программирования. В нем все является либо объектами, либо свойствами объектов. Даже если вы используете процедурный подход к программированию (создаете отдельные функции и оперируете ими), вы все равно создаете объекты, т.к. в яваскипте любая функция - это объект. Т.е. вы можете вызвать ее через оператор new и рабоать с ней как с объектом.
Когда вы создаете переменную в глобальной области видимости, то она записывается как свойство глобального объекта window. Т.е.var a = 1; и window.a = 1 эквивалентны.
Ну вот теперь многие вещи в jQuery станут понятны. Самое интересное в jQuery то, что как только вы поздключили его на страницу он у вас сразу инициализирован. Давайте посмотрим как это сделано.
1) Для начала давайте создадим наш объект, назовем его Helper, у него будет пока единственный метод init(), который должен будет инициализировать его. А делать наш объект будет всего одну вещь - находить по ID элемент на странице или получать уже найденный элемент как ноду и возвращать его:
Фишка в том, что нам надо будет обязательно инициализировать наш объект, для того чтобы он заработал, т.е. нам нужно будет где-либо на странице вызвать метод init():
alert(Helper.init('id_элемента'));
Но нам то нужно получить что-то вроде такого:
alert(Helper('id_элемента'));
Тут то нам и приходит на помощь вызов функции сразу при создании, единственное, что нам потребуется это анонимная функция (т.е. функция без имени), которая будет вызываться сразу же после создания и вспомогательная функция, которая будет инициализировать наш объект и возвращать его:
(function() { // анонимная функция var Helper = function(elem) { // вспомогательная функция return new Helper.foo.init(elem); // которая возвращает нам уже проинициализированный объект }
Helper.foo = { // наш основной объект init: function(elem) { // метод, где происходит инициализация elem = typeof elem == 'string' ? document.getElementById(elem) : elem; return elem; // метод возвращает нам ссылку на ноду } } })(); // сразу же вызываем анонимную функцию
У внимательного читателя должен возникнуть вопрос: "Откуда взялся Helper.foo? И почему именно так?". Все дело в наследовании прототипов. Вообще, прототипы в яваскрипте это довольно сложная для понимания штука. В конце я дам ссылки на ресурсы где про это можно почитать. Признаюсь, сам перечитывал раз 10, но все равно не понял до конца как они работают.
Скажу лишь, что когда мы пишем new Helper.foo.init(elem);, то не создаем новый объект с именем Helper.foo как вы могли подумать, а создаем новый объект с именем Helper.foo.init (т.к. init() - тоже функция), у которого нет ни одного метода. И чтобы использовать все методы которые мы будем добавлять в Helper.foo в дальнейшем на понадобится переопределить прототип Helper.foo.init.
Пока все это звучит очень запутанно, но я надеюсь, что когда вы увидите дальнейший код, то все поймете.
Итак, теперь у нас есть проинициализированный объект и казалось бы мы можем его начать вызывать, но (как вы должны знать) переменная Helper у нас получилась не глобальной, т.к. она находится внутри анонимной функции. Чтобы начать использовать наш Helper нам надо передать его в глобальную область видимости, вот так это сделано в jQuery:
(function() { // анонимная функция var Helper = function(elem) { // вспомогательная функция return new Helper.foo.init(elem); // которая возвращает нам уже проинициализированный объект }
Helper.foo = { // наш основной объект init: function(elem) { // метод, где происходит инициализация elem = typeof elem == 'string' ? document.getElementById(elem) : elem; return elem; // метод возвращает нам ссылку на ноду } }
// передаем переменную Helper в глобальную область видимости window.Helper = Helper; })(); // сразу же вызываем анонимную функцию
Все, теперь вы можете использовать проинициализированный объект:
Однако, если в jQuery вызвать $('#test'), то он вернет не ссылку на ноду а сам себя, т.е. объект jQuery и чтобы получить ссылку на ноду в jQuery нам придется сделать что-то вроде этого:
Почему же это не работает? Как я уже говорил выше, вспомогательная функция Helper создает новый объект с именем Helper.foo.init, а внутри нашего метода init() нет никаких других методов.
Поэтому нам надо переопределить прототип для Helper.foo.init, т.е. указать скрипту явно, что шаблоном нашего объекта является не Helper.foo.init, а Helper.foo.
Причем наш объект foo должен храниться обязательно как свойство объекта Helper иначе (если я правильно понял, прочитав кучу статей про прототипы) переопределить прототип не получится.
(function() { var Helper = function(elem) { return new Helper.foo.init(elem); }
<script type="text/javascript"> alert($$('test').getNodeName()); // выведет DIV </script>
</body>
Ну вот и все, теперь вы можете расширять свой фреймворк, добавляя туда новые методы и использовать его так же как и jQuery. Теперь вы представляете как устроен этот фреймворк.
Конечно то что я тут описал - это очень сильно упрощенная версия jQuery. Она умеет находить ноду только по ID и в ней нет кучи полезных фишек jQuery. Но я не волшебник, я только учусь. Многое еще остается в jQuery для меня не ясным, но надеюсь со временем я его таки доковыряю
You can post now and register later.
If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.
Здравствуйте, подскажите какой тег использовать для увеличения значения, пример на картинке.
Вроде, про такой тег я слышала. Если есть тег прогресс бар, значит и такое должно быть.
Question
Great Rash
Мне давно было интересно как устроен всеми любимый jQuery и вот я решил засесть за него (благо что исходники у него открытые).
И вот, по просьбе камрада mishka2 я рассказываю, что я выяснил, как работает этот фреймворк и как написать свой такой же.
Прежде всего пара фишек яваскрипта, про которые не все начинающие знают:
1) Имена функций:
В яваскрипте валидными считаются любые имена функций, которые начинаются с буквы, со знака доллара ($) и со знака подчеркивания (_). Так что когда вы используете ваш любимый jQuery, вызывая к примеру $(document), знайте, что вы вызываете функцию у которой имя $ и передаете ей в качестве аргумента document.
2) Вызов функций:
Обычно все пишут какую-нибудь функцию, к примеру:
а потом вызывают ее, но многие не знают, что в яваскрипте можно вызвать функцию сразу при создании вот таким методом:
3) Переменные и функции:
Яваскрипт - это объектно ориентированный язык программирования. В нем все является либо объектами, либо свойствами объектов. Даже если вы используете процедурный подход к программированию (создаете отдельные функции и оперируете ими), вы все равно создаете объекты, т.к. в яваскипте любая функция - это объект. Т.е. вы можете вызвать ее через оператор new и рабоать с ней как с объектом.
Когда вы создаете переменную в глобальной области видимости, то она записывается как свойство глобального объекта window. Т.е.var a = 1; и window.a = 1 эквивалентны.
Ну вот теперь многие вещи в jQuery станут понятны. Самое интересное в jQuery то, что как только вы поздключили его на страницу он у вас сразу инициализирован. Давайте посмотрим как это сделано.
1) Для начала давайте создадим наш объект, назовем его Helper, у него будет пока единственный метод init(), который должен будет инициализировать его. А делать наш объект будет всего одну вещь - находить по ID элемент на странице или получать уже найденный элемент как ноду и возвращать его:
Фишка в том, что нам надо будет обязательно инициализировать наш объект, для того чтобы он заработал, т.е. нам нужно будет где-либо на странице вызвать метод init():
Но нам то нужно получить что-то вроде такого:
Тут то нам и приходит на помощь вызов функции сразу при создании, единственное, что нам потребуется это анонимная функция (т.е. функция без имени), которая будет вызываться сразу же после создания и вспомогательная функция, которая будет инициализировать наш объект и возвращать его:
У внимательного читателя должен возникнуть вопрос: "Откуда взялся Helper.foo? И почему именно так?". Все дело в наследовании прототипов. Вообще, прототипы в яваскрипте это довольно сложная для понимания штука. В конце я дам ссылки на ресурсы где про это можно почитать. Признаюсь, сам перечитывал раз 10, но все равно не понял до конца как они работают.
Скажу лишь, что когда мы пишем new Helper.foo.init(elem);, то не создаем новый объект с именем Helper.foo как вы могли подумать, а создаем новый объект с именем Helper.foo.init (т.к. init() - тоже функция), у которого нет ни одного метода. И чтобы использовать все методы которые мы будем добавлять в Helper.foo в дальнейшем на понадобится переопределить прототип Helper.foo.init.
Пока все это звучит очень запутанно, но я надеюсь, что когда вы увидите дальнейший код, то все поймете.
Итак, теперь у нас есть проинициализированный объект и казалось бы мы можем его начать вызывать, но (как вы должны знать) переменная Helper у нас получилась не глобальной, т.к. она находится внутри анонимной функции. Чтобы начать использовать наш Helper нам надо передать его в глобальную область видимости, вот так это сделано в jQuery:
Все, теперь вы можете использовать проинициализированный объект:
Но позвольте, откуда же в jQuery берется доллар? Все очень просто - пусть у нас будет два доллара:
И вызываем:
Однако, если в jQuery вызвать $('#test'), то он вернет не ссылку на ноду а сам себя, т.е. объект jQuery и чтобы получить ссылку на ноду в jQuery нам придется сделать что-то вроде этого:
Все это потому, что все найденные элементы jQuery цепляет к себе. Ничто не мешает нам сделать так же:
Вот у нас и получится тоже самое:
Теперь давайте добавим в наш фреймворк какой-нибудь метод, например пусть у него будет имя getNodeName(), а возвращать он будет имя ноды:
Давайте попробуем при помощи нашего нового метода узнать имя ноды:
Почему же это не работает? Как я уже говорил выше, вспомогательная функция Helper создает новый объект с именем Helper.foo.init, а внутри нашего метода init() нет никаких других методов.
Поэтому нам надо переопределить прототип для Helper.foo.init, т.е. указать скрипту явно, что шаблоном нашего объекта является не Helper.foo.init, а Helper.foo.
Причем наш объект foo должен храниться обязательно как свойство объекта Helper иначе (если я правильно понял, прочитав кучу статей про прототипы) переопределить прототип не получится.
Вот теперь все заработает:
Ну вот и все, теперь вы можете расширять свой фреймворк, добавляя туда новые методы и использовать его так же как и jQuery. Теперь вы представляете как устроен этот фреймворк.
Конечно то что я тут описал - это очень сильно упрощенная версия jQuery. Она умеет находить ноду только по ID и в ней нет кучи полезных фишек jQuery. Но я не волшебник, я только учусь. Многое еще остается в jQuery для меня не ясным, но надеюсь со временем я его таки доковыряю
P.S. Что я читал:
http://javascript.ru/ecma/part8#_Prototype_
http://javascript.ru/tutorial/object/inher...type-i-prototip
http://code.jquery.com/jquery-1.4.2.js
http://dklab.ru/chicken/nablas/40.html
Link to comment
Share on other sites
5 answers to this question
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.